//using System;
//using SimpleServiceBus.Bus.Saga;
//using SimpleServiceBus.Messages.Management;
//using SimpleServiceBus.Utilities.ObjectBuilder;
//using System.Reflection;
//using Common.Logging;
//using TimeoutMessage=SimpleServiceBus.Bus.ControlMessages.TimeoutMessage;

//namespace SimpleServiceBus.Bus.Saga
//{
//    /// <summary>
//    /// A message handler that supports sagas.
//    /// </summary>
//    public class SagaMessageHandler : BaseMessageHandler<object>
//    {
//        /// <summary>
//        /// Handles a message.
//        /// </summary>
//        /// <param name="message">The message to handle.</param>
//        /// <remarks>
//        /// If the message received is has the <see cref="StartsSagaAttribute"/> defined then a new
//        /// workflow instance will be created and will be saved using the <see cref="ISagaPersister"/>
//        /// implementation provided in the configuration.  Any other message implementing 
//        /// <see cref="ISagaMessage"/> will cause the existing saga instance with which it is
//        /// associated to continue.</remarks>
//        public override void Handle(object message)
//        {
//            if (!this.NeedToHandle(message))
//                return;

//            bool sagaIsPersistent = true;

//            ISagaEntity saga = this.FindSagaUsing(message);
//            if (saga == null && message is ISagaMessage)
//                return; //couldn't find saga for ISagaMessage - do nothing

//            if (saga == null)
//            {
//                Type sagaType = GetSagaTypeForMessage(message);
//                saga = this.objectBuilder.Build(sagaType) as ISagaEntity;

//                // intentionally don't check for null - need to do handle this message
//                // if a saga couldn't be found or created, the exception will cause
//                // the message to return to the queue.
//                // if this happens every time, the message will be moved to the
//                // error queue, and the admin will know that this endpoint isn't
//                // configured properly.
//                saga.Id = this.GenerateSagaId();

//                sagaIsPersistent = false;
//            }

//            HaveSagaHandleMessage(saga, message, sagaIsPersistent);
//        }

//        public virtual bool NeedToHandle(object message)
//        {
//            if (message is ISagaMessage && !(message is TimeoutMessage))
//                return true;

//            TimeoutMessage tm = message as TimeoutMessage;
//            if (tm != null)
//            {
//                if (tm.HasNotExpired())
//                {
//                    this.MessageBus.HandleCurrentMessageLater();
//                    return false;
//                }
//                else
//                    return true;
//            }

//            if (message.GetType().GetCustomAttributes(typeof(StartsSagaAttribute), true).Length > 0)
//                return true;

//            return false;
//        }

//        public virtual ISagaEntity FindSagaUsing(object message)
//        {
//            ISagaMessage sagaMessage = message as ISagaMessage;

//            if (sagaMessage != null)
//                using (ISagaPersister persister = this.objectBuilder.Build<ISagaPersister>())
//                    return persister.GetByEndpointId(sagaMessage.SagaId);
	        
//            return null;
//        }

//        public virtual Guid GenerateSagaId()
//        {
//            return GuidCombGenerator.Generate();
//        }

//        #region helper methods

//        private void HaveSagaHandleMessage(ISagaEntity saga, object message, bool sagaIsPersistent)
//        {
//            TimeoutMessage tm = message as TimeoutMessage;
//            if (tm != null)
//                saga.Timeout(tm.State);
//            else
//                CallHandleMethodOnSaga(saga, message);

//            if (!saga.Completed)
//            {
//                using (ISagaPersister persister = this.objectBuilder.Build<ISagaPersister>())
//                    if (!sagaIsPersistent)
//                        persister.Save(saga);
//                    else
//                        persister.Update(saga);
//            }
//            else
//            {
//                if (sagaIsPersistent)
//                    using (ISagaPersister persister = this.objectBuilder.Build<ISagaPersister>())
//                        persister.Complete(saga);

//                NotifyTimeoutManagerThatSagaHasCompleted(saga);
//            }

//            LogIfSagaCompleted(saga);

//        }

//        private void NotifyTimeoutManagerThatSagaHasCompleted(ISagaEntity saga)
//        {
//            this.MessageBus.Send(new TimeoutMessage(saga, true));
//        }

//        /// <summary>
//        /// Logs that a saga has completed.
//        /// </summary>
//        /// <param name="saga">The saga that completed.</param>
//        private static void LogIfSagaCompleted(ISagaEntity saga)
//        {
//            if (saga.Completed)
//                logger.Debug(string.Format("{0} {1} has completed.", saga.GetType().FullName, saga.Id));
//        }

//        /// <summary>
//        /// Gets the type of saga associated with the specified message.
//        /// </summary>
//        /// <param name="message">The message to get the saga type for.</param>
//        /// <returns>The saga type associated with the message.</returns>
//        private static Type GetSagaTypeForMessage(object message)
//        {
//            return typeof(ISaga<>).MakeGenericType(message.GetType());
//        }

//        /// <summary>
//        /// Invokes the handler method on the saga for the message.
//        /// </summary>
//        /// <param name="saga">The saga on which to call the handle method.</param>
//        /// <param name="message">The message to pass to the handle method.</param>
//        private static void CallHandleMethodOnSaga(ISagaEntity saga, object message)
//        {
//            MethodInfo method = saga.GetType().GetMethod("Handle", new Type[] { message.GetType() });

//            if (method != null)
//                method.Invoke(saga, new object[] { message });
//        }

//        #endregion

//        #region config info

//        private IObjectBuilder objectBuilder;

//        /// <summary>
//        /// Gets/sets an <see cref="IObjectBuilder"/> that will be used for resolving
//        /// the <see cref="ISagaPersister"/> implementation to be used for
//        /// saga persistence.
//        /// </summary>
//        public virtual IObjectBuilder ObjectBuilder
//        {
//            get { return objectBuilder; }
//            set { objectBuilder = value; }
//        }

//        #endregion

//        private static readonly ILog logger = LogManager.GetLogger(typeof(SagaMessageHandler));
//    }
//}